﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;
using System.Xml;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WebConfigModifier
{
    public class WebConfigUpdater
    {
        public void HandleRequest(Stack<string> argStack, string value)
        {
            try
            {
                if (argStack == null) throw new ArgumentNullException("argStack");
                if (argStack.Count < 3) throw new ArgumentException();

                if (value == null) throw new ArgumentNullException("value");

                string webConfigFileName = argStack.Pop();
                string action = argStack.Pop();
                string xPathExpression = argStack.Pop();

                UpdateWebConfig(argStack, value, webConfigFileName, action, xPathExpression);
            }
            catch (ArgumentException exc)
            {
                Console.WriteLine(exc.Message);
                Console.WriteLine();
                DisplayUsage();
                throw new UsageException("Incorrect usage.", exc);
            }
            catch (UsageException exc)
            {
                Console.WriteLine(exc.Message);
                Console.WriteLine();
                DisplayUsage();
                throw;
            }
            catch (Exception exc)
            {
                Console.WriteLine(exc.Message);
                throw;
            }
        }

        private static void UpdateWebConfig(Stack<string> argStack, string value, string webConfigFileName, string action, string xPathExpression)
        {
            XDocument doc = LoadWebConfig(webConfigFileName);

            DocumentModifier modifier = new DocumentModifier(doc);

            if (action == "/element")
            {
                modifier.ReplaceElementValue(xPathExpression, value);
            }
            else if (action == "/attribute")
            {
                if (!argStack.Any()) throw new UsageException();
                string attributeName = argStack.Pop();

                modifier.ReplaceAttributeValue(xPathExpression, attributeName, value);
            }
            else
            {
                throw new UsageException(string.Format("Unknown action '{0}'", action));
            }

            SaveWebConfig(webConfigFileName, doc);
        }

        private static XDocument LoadWebConfig(string webConfigFileName)
        {
            string xml = File.ReadAllText(webConfigFileName);
            XDocument doc = XDocument.Parse(xml);
            return doc;
        }

        private static void SaveWebConfig(string webConfigFileName, XDocument doc)
        {
            XmlWriterSettings settings = new XmlWriterSettings
            {
                Indent = true,
                NewLineChars = Environment.NewLine,
                NewLineHandling = System.Xml.NewLineHandling.Replace,
                NewLineOnAttributes = false,
            };
            using (var writer = XmlWriter.Create(webConfigFileName, settings))
            {
                doc.WriteTo(writer);
            }
        }

        private static bool ParseCommandLineArguments(string[] args, out string webConfigFilename, out string action, out string key)
        {
            webConfigFilename = null;
            action = null;
            key = null;
            if (args.Length != 3) return false;

            webConfigFilename = args[0];
            action = args[1];
            key = args[2];
            return true;
        }

        private static void DisplayUsage()
        {
            Console.WriteLine("usage:");
            Console.WriteLine("  echo <value> | WebConfigModifier.exe <path to web.config> /element <xPathToElement>");
            Console.WriteLine("  type <filename> | WebConfigModifier.exe <path to web.config> /element <xPathToElement>");
            Console.WriteLine("  echo <value> | WebConfigModifier.exe <path to web.config> /attribute <xPathToElement> <attributeName>");
            Console.WriteLine();
            Console.WriteLine("e.g.:");
            Console.WriteLine();
            Console.WriteLine("  To replace individual connection strings, replace the providerName and connectionString attributes:");
            Console.WriteLine("    echo System.Data.SqlClient | WebConfigModifier.exe Samples\\Mvc2.Vanilla.Web.config /attribute /configuration/connectionStrings/add[@name='ApplicationServices'] providerName");
            Console.WriteLine("    echo \"data source=.\\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|different_aspnetdb.mdf;User Instance=true\" | WebConfigModifier.exe Samples\\Mvc2.Vanilla.Web.config /attribute /configuration/connectionStrings/add[@name='ApplicationServices'] connectionString");
            Console.WriteLine();
            Console.WriteLine("  To replace the entire connectionStrings document element from a file:");
            Console.WriteLine("    type Samples\\connectionStrings.xml | WebConfigModifier.exe Samples\\Mvc2.Vanilla.Web.config /element /configuration/connectionStrings");
        }
    }
}
